home *** CD-ROM | disk | FTP | other *** search
- ;=========================================================================
- ; SCALE1.ASM By John A. Slagel, jas37876@uxa.cso.uiuc.edu.
- ; This is some code to do bitmap scaling on an 256 color bitmap. This can
- ; be used to write to VGA memory or a virtual page in system memory by
- ; simply changing the ScreenPtr and BytesPerLine variables. It can scale a
- ; bitmap of any size down to 2 pixels wide, or up to thousands of pixels
- ; wide. It performs complete clipping, with only a small constant amount
- ; of time to clip, no matter how huge the image is. The inner scanline
- ; loop has been optimized for no memory accesses, except to read or
- ; write a pixel. This uses MASM 5.1 features, and can be compiled in any
- ; memory model by changing the .MODEL line, but make sure that you always
- ; pass a far pointer to the bitmap data, regardless of memory model.
- ; C-callable as:
- ; void SCALE1( int X, int Y, int DW, int DY,
- ; int SW, int SH, void far * Bitmap );
- ; X,Y are the upper left-hand coordinates of where to draw the bitmap.
- ; DW,DH are the width and height of the SCALEed bitmap
- ; SW,SH are the width and height of the source bitmap.
- ; Bitmap is a pointer to the bitmap bits.
- ;
- ;==========================================================================
- .MODEL LARGE, C
- .386
-
- .DATA
- ; Make these externs if you want your program to change them.
- ClipLt DW 20 ; Left clipping boundry
- ClipRt DW 300 ; Right clipping boundry
- ClipTp DW 20 ; Top clipping boundry
- ClipBt DW 190 ; Bottom clipping boundry
- ScreenPtr DD 0A0000000h ; Where to draw in memory.
- BytesPerLine DW 320 ; Bytes per scanline
-
- .CODE
-
- SCALE1 PROC FAR USES DS DI SI, DestX:WORD, DestY:WORD, DestWidth:WORD, DestHeight:WORD, SourceWidth:WORD, SourceHeight:WORD, Bitmap:FAR PTR
- LOCAL DecisionX:WORD, DecisionY:WORD, ClippedWidth:WORD, ClippedHeight:WORD, SourceWidth2:WORD
-
- mov ax, @DATA
- mov ds, ax
-
- cmp DestWidth, 2 ; If destination width is less than 2
- jl Done ; then don't draw it.
-
- cmp DestHeight, 2 ; If destination height is less than 2
- jl Done ; then don't draw it.
-
- mov ax, DestY ; If it is completely below the
- cmp ax, ClipBt ; lower clip bondry,
- jg Done ; then don't draw it.
-
- add ax, DestHeight ; If it is above clip boundries
- dec ax ; then don't draw it.
- cmp ax, ClipTp
- jl Done
-
- mov ax, DestX ; If it is to the right of the
- mov cx, ClipRt ; right clip boundry
- cmp ax, ClipRt ; then don't draw it.
- jg Done
-
- add ax, DestWidth ; If it is completely to the left
- dec ax ; of the left clip boundry,
- cmp ax, ClipLt ; then don't draw it.
- jl Done
-
- lfs si, Bitmap ; Make FS:SI point to bitmap data
-
- mov ax, DestWidth ; ClippedWidth is initially set to
- mov ClippedWidth, ax ; the requested dest width.
-
- shl ax,1 ; Initialize the X decision var
- neg ax ; to be -2*DestWidth
- mov DecisionX, ax ;
-
- mov ax, DestHeight ; ClippedHeight is initially set to
- mov ClippedHeight, ax ; the requested dest size.
-
- shl ax,1 ; Initialize the Y decision var
- neg ax ; to be -2*DestHeight
- mov DecisionY, ax ;
-
- movsx eax, ClipTp ; If Y is below the top
- mov edx, eax ; clipping boundry, then we don't
- sub dx, DestY ; need to clip the top, so we can
- js NoTopClip ; jump over the clipping stuff.
-
- mov DestY, ax ; This block performs clipping on the
- sub ClippedHeight, dx ; top of the bitmap. I have heavily
- movsx ecx, SourceHeight ; optimized this block to use only 4
- imul ecx, edx ; 32-bit registers, so I'm not even
- mov eax, ecx ; gonna try to explain what it's doing.
- mov edx, 0 ; But I can tell you what results from
- movsx ebx, DestHeight ; this: The DecisionY var is updated
- idiv ebx ; to start at the right clipped row.
- movsx edx, SourceWidth ; Y is moved to the top clip
- imul edx, eax ; boundry. ClippedHeight is lowered since
- add si, dx ; we won't be drawing all the requested
- imul eax, ebx ; rows. SI is changed to point over
- sub ecx, eax ; the bitmap data that is clipped off.
- sub ecx, ebx ;
- shl ecx, 1 ;
- mov DecisionY, cx ; <end of top clipping block >
-
- NoTopClip:
- mov ax, DestY ; If the bitmap doesn't extend over the
- add ax, ClippedHeight ; bottom clipping boundry, then we
- dec ax ; don't need to clip the bottom, so we
- cmp ax, ClipBt ; can jump over the bottom clip code.
- jle NoBottomClip ;
-
- mov ax, ClipBt ; Clip off the bottom by reducing the
- sub ax, DestY ; ClippedHeight so that the bitmap won't
- inc ax ; extend over the lower clipping
- mov ClippedHeight, ax ; boundry.
-
- NoBottomClip:
- movsx eax, ClipLt ; If X is to the left of the
- mov edx, eax ; top clipping boundry, then we don't
- sub dx, DestX ; need to clip the left, so we can
- js NoLeftClip ; jump over the clipping stuff.
-
- mov DestX, ax ; This block performs clipping on the
- sub ClippedWidth, dx ; left of the bitmap. I have heavily
- movsx ecx, SourceWidth ; optimized this block to use only 4
- imul ecx, edx ; 32-bit registers, so I'm not even
- mov eax, ecx ; gonna try to explain what it's doing.
- mov edx, 0 ; But I can tell you what results from
- movsx ebx, DestWidth ; this: The DecisionX var is updated
- idiv ebx ; to start at the right clipped column.
- add si, ax ; X is moved to the left clip
- imul eax, ebx ; boundry. ClippedWidth is reduced since
- sub ecx, eax ; we won't be drawing all the requested
- sub ecx, ebx ; cols. SI is changed to point over
- shl ecx, 1 ; the bitmap data that is clipped off.
- mov DecisionX, cx ; <end of left clipping block >
-
- NoLeftClip:
- mov ax, DestX ; If the bitmap doesn't extend over the
- add ax, ClippedWidth ; right clipping boundry, then we
- dec ax ; don't need to clip the right, so we
- cmp ax, ClipRt ; can jump over the right clip code.
- jle NoClipRight ;
-
- mov ax, ClipRt ; Clip off the right by reducing the
- sub ax, DestX ; ClippedWidth so that the bitmap won't
- inc ax ; extend over the right clipping
- mov ClippedWidth, ax ; boundry.
-
- ;Calculate starting video address
- NoClipRight:
- les di, ScreenPtr ; Make ES:DI point to the dest memory.
- mov ax, DestY ; Calculated as:
- imul ax, BytesPerLine ;
- add di, ax ; DI=DI+Y*BytesPerScanLine+X
- add di, DestX ; ES:DI -> Video memory
-
- ; Multiply all the widths, etc by 2 to reduce inner loop calcs.
- shl DestWidth,1 ; Dest width *= 2
- shl SourceHeight,1 ; SourceHeight *= 2
- shl DestHeight,1 ; DestHeight *= 2
- mov ax, SourceWidth
- shl ax, 1
- mov SourceWidth2, ax ; Source Width *= 2
-
- ALIGN 4 ; Since this point gets jumped to a lot,
- ; make sure that it is DWORD aligned.
- RowLoop:
- push si ; Save the starting source index
- push di ; Save the starting dest index
- push bp ; Save the current base pointer
-
- mov bx, DecisionX ; Use BX for X decision variable
- mov cx, ClippedWidth ; Use CX for column counter
- mov dx, SourceWidth2 ; Use DX for source width * 2
- mov bp, DestWidth ; Use GS for dest width * 2
- mov al, fs:[si] ; Get the first source pixel
-
- ; From this point to DoneWithScanLine is the critical inner-loop.
- ALIGN 4 ; Common jump point... align for speed.
- ScanLineLoop:
- stosb ; Draw a pixel
- dec cx ; Decrement width counter
- jz DoneWithScanLine ; See if we're done with this scan line
- add bx, dx ; Increment the decision variable
- js ScanLineLoop ; Do we increment the source pixel?
-
- IncSourceCol:
- inc si ; Go on to next source pixel
- sub bx, bp ; Decrement the decision variable
- jns IncSourceCol ; See if we need to skip another source pixel
- mov al, fs:[si] ; Get the next source pixel
- jmp ScanLineLoop ; Start drawing this pixel
-
- DoneWithScanLine:
- pop bp ; Restore BP to access variables
- pop di ; Restore DI to top row of screen
- pop si ; Restore SI to top row of source bits
-
- add di, BytesPerLine
- mov bx, DecisionY ; Use BX for the Y decision variable
- add bx, SourceHeight ; Increment the Y decision variable
- js NextRow ; Jump if we're in the same source row.
-
- IncSourceRow:
- add si, SourceWidth ; Move to next source row
- sub bx, DestHeight ; Decrement Y decision variable
- jns IncSourceRow ; See if we skip another source row
-
- NextRow:
- mov DecisionY, bx ; Free up BX for RowLoop
- dec ClippedHeight ; If we're not at last row
- jnz RowLoop ; then do another row
- Done:
- ret ; We're done!
-
- SCALE1 ENDP
-
- END
-
-
-